package ymy;

import ymy.BaseSimulator.StageResult;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Main {

    private static Set<Integer> sameKeySet = new HashSet<>();
    private static boolean flag = false;

    public static void main(String[] args) {

        LocalDateTime time = LocalDateTime.now();

        // 随机仿真：停放车辆&移动车辆

        // for (int p = RandomConfig.PARK_VEHICLES_MIN; p <= RandomConfig.PARK_VEHICLES_MAX; p += RandomConfig.PARK_STEP) {
        //     for (int m = RandomConfig.MOVE_VEHICLES_MIN; m <= RandomConfig.MOVE_VEHICLES_MAX; m += RandomConfig.MOVE_STEP) {
        //         randomSimulation(p, m);
        //     }
        // }
        //
        // randomSimulation(160, 100);

        System.out.println("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++");
        System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");

        // 特定仿真：停放车辆&&移动车辆
        // LogUtil.writeLog("[1]SPECIFIC SIMULATION AT " + time.toString(), false);
        // for (int i = 0; i < SpecificConfig.PARK_VEHICLES_ARRAY.length; i++) {
        //     for (int j = 0; j < SpecificConfig.MOVE_VEHICLES_ARRAY.length; j++) {
        //         specificSimulationOV(i, j);
        //     }
        // }
        //
        // LogUtil.writeLog("[2]SPECIFIC SIMULATION AT " + time.toString(), false);
        // for (int j = 0; j < SpecificConfig.MOVE_VEHICLES_ARRAY.length; j++) {
        //     for (int i = 0; i < SpecificConfig.PARK_VEHICLES_ARRAY.length; i++) {
        //         specificSimulationOV(i, j);
        //     }
        // }

        LogUtil.writeLog("[1]SPECIFIC SIMULATION AT " + time.toString(), false);
        LogUtil.writeLog("[1]SPECIFIC SIMULATION AT " + time.toString(), true);
        for (int p = SpecificConfig.PARK_VEHICLES_MIN; p <= SpecificConfig.PARK_VEHICLES_MAX; p += SpecificConfig.PARK_STEP) {
            for (int m = SpecificConfig.MOVE_VEHICLES_MIN; m <= SpecificConfig.MOVE_VEHICLES_MAX; m += SpecificConfig.MOVE_STEP) {
                specificSimulation(p, m);
            }
        }

        sameKeySet.clear();
        flag = false;

        LogUtil.writeLog("[2]SPECIFIC SIMULATION AT " + time.toString(), false);
        LogUtil.writeLog("[2]SPECIFIC SIMULATION AT " + time.toString(), true);
        for (int m = SpecificConfig.MOVE_VEHICLES_MIN; m <= SpecificConfig.MOVE_VEHICLES_MAX; m += SpecificConfig.MOVE_STEP) {
            for (int p = SpecificConfig.PARK_VEHICLES_MIN; p <= SpecificConfig.PARK_VEHICLES_MAX; p += SpecificConfig.PARK_STEP) {
                specificSimulation(p, m);
            }
        }

        // 特殊测试用例
        // GeneralConfig.LINK_SELECT_TYPE = GeneralConfig.LD;
        // specificSimulation(120, 40);
        //
        // GeneralConfig.LINK_SELECT_TYPE = GeneralConfig.FD;
        // specificSimulation(120, 40);
        //
        // GeneralConfig.LINK_SELECT_TYPE = GeneralConfig.QP;
        // specificSimulation(120, 40);
    }

    public static void specificSimulation(int pc, int mc) {
        System.out.println("=====================================================");
        SpecificConfig.PARK_VEHICLES = pc;
        SpecificConfig.MOVE_VEHICLES = mc;

        Environment env = new Environment();
        env.initEnvironment();
        if (GeneralConfig.DEBUG_INFO)
            System.out.println(env);

        SpecificSimulator ss = new SpecificSimulator(env);

        GeneralConfig.SIMULATION_TYPE = GeneralConfig.MOVE_ONLY;
        StageResult sr1 = ss.specificSimulationProcess(false);
        ss.clearStage();
        GeneralConfig.SIMULATION_TYPE = GeneralConfig.PARK_MOVE;
        StageResult sr2 = ss.specificSimulationProcess(false);

        compareStageResult(sr1, sr2);

        System.out.println("[INFO] SPECIFIC SIMULATION TYPE = MOVE_ONLY");
        System.out.printf("[INFO] SPECIFIC SIMULATION INFO: (PARK--%d, MOVE--%d)\n", ss.getParkVehiclesCount(), ss.getMoveVehiclesCount());
        System.out.println(sr1);
        LogUtil.writeStageResultLog(sr1, true);

        System.out.println("----------------------------------------------------");
        System.out.println("[INFO] SPECIFIC SIMULATION TYPE = PARK_MOVE");
        System.out.printf("[INFO] SPECIFIC SIMULATION INFO: (PARK--%d, MOVE--%d)\n", ss.getParkVehiclesCount(), ss.getMoveVehiclesCount());
        System.out.println(sr2);
        LogUtil.writeStageResultLog(sr2, false);
    }

    public static void specificSimulationOV(int pindex, int mindex) {
        System.out.println("=====================================================");
        SpecificConfig.PARK_VEHICLES_OV = SpecificConfig.PARK_VEHICLES_ARRAY[pindex];
        SpecificConfig.MOVE_VEHICLES_OV = SpecificConfig.MOVE_VEHICLES_ARRAY[mindex];

        Environment env = new Environment();
        env.initEnvironment();
        if (GeneralConfig.DEBUG_INFO)
            System.out.println(env);

        SpecificSimulator ss = new SpecificSimulator(env);

        GeneralConfig.SIMULATION_TYPE = GeneralConfig.MOVE_ONLY;
        StageResult sr1 = ss.specificSimulationProcess(true);
        ss.clearStage();
        GeneralConfig.SIMULATION_TYPE = GeneralConfig.PARK_MOVE;
        StageResult sr2 = ss.specificSimulationProcess(true);

        compareStageResult(sr1, sr2);

        System.out.println("[INFO] SPECIFIC SIMULATION TYPE = MOVE_ONLY");
        System.out.printf("[INFO] SPECIFIC SIMULATION INFO: (PARK--%d, MOVE--%d)\n", ss.getParkVehiclesCount(), ss.getMoveVehiclesCount());
        System.out.println(sr1);
        LogUtil.writeStageResultLog(sr1, true);

        System.out.println("----------------------------------------------------");
        System.out.println("[INFO] SPECIFIC SIMULATION TYPE = PARK_MOVE");
        System.out.printf("[INFO] SPECIFIC SIMULATION INFO: (PARK--%d, MOVE--%d)\n", ss.getParkVehiclesCount(), ss.getMoveVehiclesCount());
        System.out.println(sr2);
        LogUtil.writeStageResultLog(sr2, false);
    }

    public static void randomSimulation(int pc, int mc) {
        System.out.println("====================================================");
        RandomConfig.PARK_VEHICLES = pc;
        RandomConfig.MOVE_VEHICLES = mc;

        Environment env = new Environment();
        env.initEnvironment();
        if (GeneralConfig.DEBUG_INFO)
            System.out.println(env);

        RandomSimulator rs = new RandomSimulator(env);

        GeneralConfig.SIMULATION_TYPE = GeneralConfig.MOVE_ONLY;
        StageResult sr1 = rs.randomSimulationProcess(false);
        rs.clearStage();
        GeneralConfig.SIMULATION_TYPE = GeneralConfig.PARK_MOVE;
        StageResult sr2 = rs.randomSimulationProcess(false);

        compareStageResult(sr1, sr2);

        System.out.println("[INFO] RANDOM SIMULATION TYPE = MOVE_ONLY");
        System.out.printf("[INFO] RANDOM SIMULATION INFO: (PARK--%d, MOVE--%d)\n", rs.getParkVehiclesCount(), rs.getMoveVehiclesCount());
        System.out.println(sr1);
        LogUtil.writeStageResultLog(sr1, true);

        System.out.println("----------------------------------------------------");
        System.out.println("[INFO] RANDOM SIMULATION TYPE = PARK_MOVE");
        System.out.printf("[INFO] RANDOM SIMULATION INFO: (PARK--%d, MOVE--%d)\n", rs.getParkVehiclesCount(), rs.getMoveVehiclesCount());
        System.out.println(sr2);
        LogUtil.writeStageResultLog(sr2, true);
    }

    public static void compareStageResult(StageResult sr1, StageResult sr2) {
        Map<Integer, BaseSimulator.PathResult> srmap1 = sr1.getPathResults();
        Map<Integer, BaseSimulator.PathResult> srmap2 = sr2.getPathResults();

        Set<Integer> keys = srmap1.keySet();

        int count = 0;
        double sumDelay1 = 0.0;
        double sumDelay2 = 0.0;
        double sumHop1 = 0.0;
        double sumHop2 = 0.0;
        double sumQuality1 = 0.0;
        double sumQuality2 = 0.0;
        double sumDist1 = 0.0;
        double sumDist2 = 0.0;

        if (!sameKeySet.isEmpty())
            keys = sameKeySet;

        for (Integer key : keys) {
            BaseSimulator.PathResult pr1 = srmap1.get(key);
            BaseSimulator.PathResult pr2 = srmap2.get(key);
            if (pr1 != null && pr1.isConnected() && pr2 != null && pr2.isConnected()) {
                // System.out.println("MOVE_ONLY");
                // System.out.println(pr1);
                // System.out.println("PARK_MOVE");
                // System.out.println(pr2);
                sumDelay1 += pr1.getDelay();
                sumHop1 += pr1.getHops();
                sumQuality1 += pr1.getQuality();
                sumDelay2 += pr2.getDelay();
                sumHop2 += pr2.getHops();
                sumQuality2 += pr2.getQuality();
                sumDist1 += pr1.getDist();
                sumDist2 += pr2.getDist();
                count++;

                if (!flag)
                    sameKeySet.add(key);
            }
        }

        flag = true;

        sr1.setSdelay(sumDelay1 / count);
        sr1.setSquality(sumQuality1 / count);
        sr1.setShops(sumHop1 / count);
        sr1.setSdist(sumDist1 / count);

        sr2.setSdelay(sumDelay2 / count);
        sr2.setSquality(sumQuality2 / count);
        sr2.setShops(sumHop2 / count);
        sr2.setSdist(sumDist2 / count);

        System.out.println("<" + count + "/" + keys.size() + ">");
        System.out.println("[INFO]===MOVE_ONLY===>>>");
        System.out.printf("  Delay = %.3f\n", (sumDelay1 / count));
        System.out.printf("  Hops = %.3f\n", (sumHop1 / count));
        System.out.printf("  Quality = %.3f\n", (sumQuality1 / count));
        System.out.printf("  Dist = %.3f\n", (sumDist1 / count));
        System.out.println("[INFO]===PARK_MOVE===>>>");
        System.out.printf("  Delay = %.3f\n", (sumDelay2 / count));
        System.out.printf("  Hops = %.3f\n", (sumHop2 / count));
        System.out.printf("  Quality = %.3f\n", (sumQuality2 / count));
        System.out.printf("  Dist = %.3f\n", (sumDist2 / count));
    }
}
